/*   The MIT License
 *   
 *   Carina Engine
 *   Copyright (c) 2009 2010 2011 2012 Zdravko Velinov
 *   
 *   Permission is hereby granted, free of charge, to any person obtaining a copy
 *   of this software and associated documentation files (the "Software"), to deal
 *   in the Software without restriction, including without limitation the rights
 *   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 *   copies of the Software, and to permit persons to whom the Software is
 *   furnished to do so, subject to the following conditions:
 *
 *   The above copyright notice and this permission notice shall be included in
 *   all copies or substantial portions of the Software.
 *
 *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 *   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 *   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 *   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 *   THE SOFTWARE.
 */

#ifndef CAMERA_HH_
#define CAMERA_HH_

#include "carina/math.hh"

#include "carina/renderer-base.hh"

#include <iostream>

namespace Carina
{
class Camera
{
    RendererPtr m_Renderer;

    float       m_NearPlane,
                m_FarPlane;
    unsigned    m_Height,
                m_Width;
    Vector3     m_Position;
    float       m_Yaw,
                m_Pitch;

    Vector4     m_Frustum[6];
    Vector3     m_ForwardVector;
    Vector3     m_LeftVector;

    Matrix4     ProjectionMatrix;
    Matrix4     ViewMatrix;
    Matrix4     TransformMatrix;
    Matrix4     InvTransformMatrix;
public:
    Camera(const RendererPtr& m_Renderer, float n, float f, unsigned w, unsigned h);
    ~Camera();

    void resize(unsigned w, unsigned h) 
    {
        m_Height = h;
        m_Width = w;

        _resize();
    }

    float getYaw() const { return m_Yaw; }
    float getPitch() const { return m_Pitch; }

    float getNearDistance() const { return m_NearPlane; }
    float getFarDistance() const { return m_FarPlane; }
    unsigned getHeight() const { return m_Height; }
    unsigned getWidth() const { return m_Width; }
    Matrix4 getProjectionMatrix() const { return ProjectionMatrix; }
    Matrix4 getViewMatrix() const { return ViewMatrix; }
    Matrix4 getTransformMatrix() const { return TransformMatrix; }
    Matrix4 getInvTransformMatrix() const { return InvTransformMatrix; }

    void translate(const Vector3& vec);
    void rotate(float yaw, float pitch);
    void setPosition(const Vector3& vec);
    Vector3 getPosition() const { return m_Position; }
    const Vector4* getFrustum() const { return m_Frustum; }

    Vector3 getForwardVector() const { return m_ForwardVector; }
    Vector3 getLeftVector() const { return m_LeftVector; }

private:
    void _resize();
    void _updateFrustum();
};

typedef shared_ptr<Camera> CameraPtr;
}

#endif /* CAMERA_HH_ */
